using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data;

namespace FluentSilverlight.Interceptors
{
    public class ButtonBaseVisibilityInterceptor<TModel, TView> : DependencyObject
        where TView : ButtonBase
    {
        private readonly TModel model;
        private readonly string modelPropertyName;
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<EventArgs<Visibility>> ViewVisiblilityChanged;
        public event EventHandler<EventArgs<bool>> ModelIsVisibleChanged;

        public ButtonBaseVisibilityInterceptor(TView element, TModel model, string modelPropertyName)
        {
            this.model = model;

            var notifyPropChg = model as INotifyPropertyChanged;

            if (notifyPropChg != null)
                notifyPropChg.PropertyChanged += OnModelPropertyChanged;

            this.modelPropertyName = modelPropertyName;

            var binding = new Binding("Visibility") { Source = this, Mode = BindingMode.TwoWay };
            element.SetBinding(VisibilityProperty, binding);
        }

        public void Initialize()
        {
            OnModelPropertyChanged(this, new PropertyChangedEventArgs(modelPropertyName));
        }

        public void SetModelIsVisible(bool isVisible)
        {
            var prop = model.GetType().GetProperty(modelPropertyName);
            prop.SetValue(model, isVisible, null);
        }

        public void SetViewVisibility(Visibility visibility)
        {
            Value = visibility;
        }

        public static readonly DependencyProperty VisibilityProperty =
            DependencyProperty.RegisterAttached("Visibility", typeof(Visibility), typeof(ButtonBaseVisibilityInterceptor<TModel, TView>),
                                                new PropertyMetadata(OnVisibilityChangedStatic));

        private static void OnVisibilityChangedStatic(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ButtonBaseVisibilityInterceptor<TModel, TView>)d).OnVisibilityChanged((Visibility)e.NewValue);
        }

        private void OnVisibilityChanged(Visibility value)
        {
            if (ViewVisiblilityChanged != null)
                ViewVisiblilityChanged(this, new EventArgs<Visibility>(value));
        }

        void OnModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName != modelPropertyName) return;

            var modelValue = (bool)model.GetType().GetProperty(modelPropertyName).GetValue(model, null);

            if (ModelIsVisibleChanged != null)
                ModelIsVisibleChanged(this, new EventArgs<bool>(modelValue));
        }

        public object Value
        {
            get { return GetValue(VisibilityProperty); }
            set
            {
                var oldValue = GetValue(VisibilityProperty);

                if (oldValue == value) return;

                SetValue(VisibilityProperty, value);

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            }
        }
    }
}